#include <string>
#include "string.h"
#include <ctype.h>
#include "lexic_analyzer.h"
#include "main_container.h"
#include "errors_warnings.h"

extern MainContainer * CompilerData;

LexicAnalyzer::LexicAnalyzer() {
	currentLoadedFile=NULL;
}

LexicAnalyzer::~LexicAnalyzer() { }

// This method executes lexical analysis.
bool LexicAnalyzer::LexicAnalysis(void) {
	return LexicAnalyseFiles();
}

// This method will make lexical analysis of all files in the current project.
bool LexicAnalyzer::LexicAnalyseFiles(void) {

#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("LexicAnalyseFiles");
#endif

	bool filesCorrect = true;
	// call LexicAnalyseFile() for every loaded file in the project
	for(int i=0; i < CompilerData->LoadedFiles->GetCount(); i++)	{
		currentLoadedFile = CompilerData->LoadedFiles->GetData(i);
		if(!LexicAnalyseFile())	filesCorrect = false;
	}
	// write end of project
	LexicUnit endOfProject;
	endOfProject.id = CompilerData->Units->uniformCharacters->GetCount();
	endOfProject.sourceColumnId = currentLoadedFile->GetCurrentColumn();
	endOfProject.sourceLineId = currentLoadedFile->GetCurrentLine();
	endOfProject.sourceFileId = currentLoadedFile->GetCurentFileID();
	endOfProject.type = LUTypeSpecialType; 
	endOfProject.subtype = 1; //endOfProject
	// add new lexic unit to table of uniform units 
	CompilerData->Units->AddUnit(endOfProject);

#ifdef TRACE
	CompilerData->LogTrace->ReportExit("LexicAnalyseFiles");
#endif

	return filesCorrect;
}

// This method makes lexical analysis for current file.
bool LexicAnalyzer::LexicAnalyseFile(void) {

#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("LexicAnalyseFile");
#endif

	int c;
	bool errorNotFound = true;
	while ((c = currentLoadedFile->LookNextCharacter()) != -1)	{

#ifdef TRACE
		CompilerData->LogTrace->ReportLine("Looking next character...");
		CompilerData->LogTrace->ReportValue("c", c);
#endif

		if ((isalpha(c)) || (c == '_'))	{                                 // if c is Identifier or Bool constant (true/false)or Keyword
			if(!LexicIdentifier())	errorNotFound = false;
  }	else if (isdigit(c))	{                                          // if c is Integer or Float constant
			if(!LexicNumericConstant())	errorNotFound = false;
		}	else if (c=='"')	{                                              // if c is String constant
			if(!LexicStringConstant())	errorNotFound = false;
		}	else	{                                                          // comments, special characters or operators
			char spec[] = { '(', ')', ',', '.', '/', ':', ';', '[', ']', '{', '}', '\0' };
			if (CharactersSearch(spec, (int)strlen(spec), (char)c))	{
				if (c=='/')	{
					// read '/', look the next character and rewind character
					currentLoadedFile->GetNextCharacter();
					c = currentLoadedFile->LookNextCharacter();
					currentLoadedFile->RewindCharacter();
					// if comments
					if ((c == '/') || (c == '*'))	{ 
						if(!LexicSpecialCharacter())	errorNotFound = false;
					}	else {                                                       // division character '/'
						if(!LexicOperator())	errorNotFound = false;
					}
				}	else if (c == '.')	{
					//// .8 is not legal number
					//// read '.', look the next character and rewind character
					//currentLoadedFile->GetNextCharacter();
					//c=currentLoadedFile->LookNextCharacter();
					//currentLoadedFile->RewindCharacter();
					//if (isdigit(c))
					//{
					//	// numeric constant .7 = 0.7
					//	if(!LexicNumericConstant())
					//	{
					//		errorNotFound=false;
					//	}
					//}
					//else
					//{
					if(!LexicSpecialCharacter())	errorNotFound = false;
					//}
				}	else	{
					if(!LexicSpecialCharacter())	errorNotFound = false;
				}
			}	else	{
				char oper[] = { '!', '%', '&', '*', '+', '-', '<', '=', '>', '^', '|', '\0' };
				// if operator
				if (CharactersSearch(oper, (int)strlen(oper), (char)c))	{
					if(!LexicOperator())	errorNotFound = false;
				}	else if (isspace(c))	{
					// read (skip) space character
					currentLoadedFile->GetNextCharacter();
				}	else {
					// character which isn't part of alphabet has been found (exp: '$')
					// and character isn't part of string

					// Error report
// ****************	// !!!!!!!!!!! nema leksicke jedinke koju bimo proslijedili !!!!!!!!!!!
// **************** // !!!!!!!!!!! ili ju stvoriti samo za ove portebe ili proslijedit NULL? !!!!!!!!!!!!!!!
					CompilerData->ErrorWarningReport->ReportError(NULL, ERR_LEX_UNKNOWN_CHAR_FOUND);
					errorNotFound = false;
					// read (skip) unknown character and continue with analyses
					currentLoadedFile->GetNextCharacter();
				}
			}
		}
	}
	// write end of file
	LexicUnit endOfFile;
	endOfFile.id=CompilerData->Units->uniformCharacters->GetCount();
	endOfFile.sourceColumnId=currentLoadedFile->GetCurrentColumn();
	endOfFile.sourceLineId=currentLoadedFile->GetCurrentLine();
	endOfFile.sourceFileId=currentLoadedFile->GetCurentFileID();
	endOfFile.type=LUTypeSpecialType; 
	endOfFile.subtype=0; //endOfFile
	// add new lexic unit to table of uniform units 
	CompilerData->Units->AddUnit(endOfFile);

#ifdef TRACE
	if(errorNotFound) CompilerData->LogTrace->ReportLine("Lexical analysis successfuly finished.");
	else	CompilerData->LogTrace->ReportLine("Lexical analysis finished unsuccessfuly.");
	CompilerData->LogTrace->ReportExit("LexicAnalyseFile");
#endif

	return errorNotFound;
}

// This method returns true if character 'c' is element of 'field'
bool LexicAnalyzer::CharactersSearch(char *field,int lenght,char c) {
// not so important method to be traced
//#ifdef TRACE
//	CompilerData->LogTrace->ReportEntry("CharactersSearch");
//#endif
	for(int i = 0; i < lenght; ++i)	{
		if (field[i] == c) return true;
  else if (field[i] > c) {
			// if it hasn't been found yet, it won't be found because
			// all other ASCII codes are bigger
			return false;
		}
	}
//#ifdef TRACE
//	CompilerData->LogTrace->ReportExit("CharactersSearch");
//#endif
	return false;
}

// This method checks if the current lexic unit is an operator
bool LexicAnalyzer::LexicOperator() {	

#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("LexicOperator");
#endif

	Operators operatorType;
	SpecialCharacters specialType;
	bool isOperator = false;
	bool isSpecial = false;
	bool error = false;
	// populate the generic lexic unit now because we might need to 
	// look at the next character in the currentLoadedFile and that 
	// would change these parameters
	LexicUnit unit;
	unit.id = CompilerData->Units->uniformCharacters->GetCount();
	unit.sourceColumnId = currentLoadedFile->GetCurrentColumn();
	unit.sourceLineId = currentLoadedFile->GetCurrentLine();
	unit.sourceFileId = currentLoadedFile->GetCurentFileID();
	// CHECK the type of the operator
	int currentChar = currentLoadedFile->GetNextCharacter();
 int nextChar;
	switch (currentChar)	{
  case '|':
 		nextChar = currentLoadedFile->LookNextCharacter();
 		if (nextChar != '|')	{	
				///this is error!!!
				error = true;
				CompilerData->ErrorWarningReport->ReportError(&unit, ERR_LEX_MISSPELLED_OPERATOR_OR);
				//GlobalObject.Error.Report("Misspelled operator OR (||)");
				// we'll asume that the user wanted to write '||'
				// but forgot to do so.
				// so we won't read the next char and we'll let the main loop 
				// parse from there
			}	else	{
				// this IS the OR operator, so read the second '|'
				currentLoadedFile->GetNextCharacter();
			}
			isOperator = true;
			operatorType = OperatorOr;
		 break;
	 case '&':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar != '&')	{	
				///this is  error!!!
				error = true;
				CompilerData->ErrorWarningReport->ReportError(&unit, ERR_LEX_MISSPELLED_OPERATOR_AND);
				//GlobalObject.Error.Report("Misspelled operator AND (&&)");
				// we'll asume that the user wanted to write '&&'
				// but forgot to do so.
				// so we won't read the next char and we'll let the main loop 
				// parse from there
			}	else	{
				// this IS the AND operator, so read the second '&'
				currentLoadedFile->GetNextCharacter();
			}
			isOperator = true;
			operatorType = OperatorAnd;
		 break;
	 case '<':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar == '=')	{
				isOperator = true;
				operatorType = OperatorLessThanOrEqualTo;
				currentLoadedFile->GetNextCharacter();
			}	else	{
				isOperator = true;
				operatorType = OperatorLessThan;
			}
		 break;
 	case '>':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar == '=')	{
				isOperator = true;
				operatorType = OperatorGreaterThanEqualTo;
				currentLoadedFile->GetNextCharacter();
			}	else	{
				isOperator = true;
				operatorType = OperatorGreaterThan;
			}
		 break;
	 case '^':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar == '^')	{
				isOperator = true;
				operatorType = OperatorXor;
				currentLoadedFile->GetNextCharacter();
			}	else	{
				isOperator = true;
				operatorType = OperatorExponentiation;
			}
		 break;
	 case '-':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar == '>')	{
				// special character
				isSpecial = true;
				specialType = SpecialCharacterTheArrowOperator;
				currentLoadedFile->GetNextCharacter();
			}	else	{
				// normal subtraction operator
				isOperator = true;
				operatorType = OperatorSubtraction;
			}
	 	break;
	 case '=':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar == '=')	{
				isOperator = true;
				operatorType = OperatorEqual;
				currentLoadedFile->GetNextCharacter();
			}	else	{
				isOperator = true;
				operatorType = OperatorAssigment;
			}
		 break;
	 case '!':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar == '=')	{
				isOperator = true;
				operatorType = OperatorNotEqual;
				currentLoadedFile->GetNextCharacter();
			}	else	{
				isOperator = true;
				operatorType = OperatorNot;
			}
		 break;
	 case '%':
			isOperator = true;
			operatorType = OperatorModulus;
		 break;
 	case '*':
			isOperator = true;
			operatorType = OperatorMultiplication;
		 break;
	 case'/':
			isOperator = true;
			operatorType = OperatorDivision;
		 break;
	 case '+':
			nextChar = currentLoadedFile->LookNextCharacter();
			if (nextChar == '-')	{
				//special character '+-'
				isSpecial = true;
				specialType = SpecialCharacterPlusOrMinus;
				currentLoadedFile->GetNextCharacter();
			}	else	{
				// assume addition operator
				isOperator = true;
				operatorType = OperatorAddition;
			}
		 break;
	}
	// error recovery - if the above code has determined that neither the input represents an operator 
	// nor special
	if (!isOperator && !isSpecial)	{

#ifdef TRACE
		CompilerData->LogTrace->ReportLine("Neither operator nor special character recognized.");
#endif

		// ignore that character
		// REPORT ERROR
		CompilerData->ErrorWarningReport->ReportError(&unit, ERR_LEX_UNRECOGNIZED_OPERATOR_SPECIAL);
		// unexpected error (logical error in main method)
	}	else	{
		// add the lexic unit to the table if needed
		if (isOperator && !isSpecial)	{
			// lexic unit is an operator
			unit.type = LUTypeOperator;
			unit.subtype = operatorType;
			CompilerData->Units->AddUnit(unit);

#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Operator is recognized.");
#endif

		}	else	{

#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Special character is recognized.");
#endif

			unit.type = LUTypeSpecialCharacter;
			unit.subtype = specialType;
			CompilerData->Units->AddUnit(unit);
		} 
	}

#ifdef TRACE
	CompilerData->LogTrace->ReportExit("LexicOperator");
#endif

	// method return false if error has been found
	return !error;
}

//this method recognises special characters and skips comments
bool LexicAnalyzer::LexicSpecialCharacter() {

#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("LexicSpecialCharacter");
#endif

	bool isSpecialCharacter = false;
	bool isComment = false;
	SpecialCharacters specialType;
	LexicUnit myUnit;
	myUnit.id = CompilerData->Units->uniformCharacters->GetCount();
	myUnit.sourceColumnId = currentLoadedFile->GetCurrentColumn();
	myUnit.sourceLineId = currentLoadedFile->GetCurrentLine();
	myUnit.sourceFileId = currentLoadedFile->GetCurentFileID();
	myUnit.type = LUTypeSpecialCharacter;
	char c = currentLoadedFile->LookNextCharacter();
	switch (c)	{
	 case ('/'):

		 //move forward for one character
		 currentLoadedFile->GetNextCharacter();

		 //comment in one row, comment is ending with '\n'
		 if (c = currentLoadedFile->LookNextCharacter() == '/')	{			
			while (1)	{
				c = currentLoadedFile->GetNextCharacter();
				if (c == '\n')	{

#ifdef TRACE
     CompilerData->LogTrace->ReportLine("end of line");
#endif

					isComment = true;
					break;
				} else if (c == -1) {

#ifdef TRACE
     CompilerData->LogTrace->ReportLine("end of file");
#endif

     isComment = true;
					break;
    }
			}
			//rewind for one character '\n'
			currentLoadedFile->RewindCharacter();
		}

		//comment in one or more rows, starting with "/*" and ending with "*/"
		else if (c = currentLoadedFile->LookNextCharacter() == '*')
		{			
			while(1)
			{
				c = currentLoadedFile->GetNextCharacter();
				//EOF or -1 is end of file
				if (c == -1)
				{
					// report unfinished comment !!!
					CompilerData->ErrorWarningReport->ReportError(&myUnit, ERR_LEX_UNFINISHED_COMMENT);
					isComment = false;
					break;
				}
				if (c == '*')
				{
					if (c = currentLoadedFile->LookNextCharacter() == '/')
					{
						//move on the end of comment
						currentLoadedFile->GetNextCharacter();
						isComment = true;
						break;
					}
				}
			}
		}
		else 
		{
			//rewind on the begining
			isComment = false;
			currentLoadedFile->RewindCharacter();
		}
		break;

	case (';'):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterSemicolon;
		isSpecialCharacter = true;
		break;

	case ('['):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterLeftSquareBracket;
		isSpecialCharacter = true;
		break;

	case (']'):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterRightSquareBracket;
		isSpecialCharacter = true;
		break;

		//+-
	case ('+'):

		currentLoadedFile->GetNextCharacter();
		if (currentLoadedFile->LookNextCharacter() == '-')
		{
			currentLoadedFile->GetNextCharacter();
			specialType = SpecialCharacterPlusOrMinus;
			isSpecialCharacter = true;
		}
		else
		{
			//rewind on the begining
			currentLoadedFile->RewindCharacter();
		}
		break;

	case ('('):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterLeftParenthesis;
		isSpecialCharacter = true;
		break;

	case (')'):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterRightParenthesis;
		isSpecialCharacter = true;
		break;

	case (','):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterComma;
		isSpecialCharacter = true;
		break;

	case ('.'):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterPeriod;
		isSpecialCharacter = true;
		break;

	case (':'):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterColon;
		isSpecialCharacter = true;
		break;

	case ('{'):

		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterLeftCurlyBrace;
		isSpecialCharacter = true;
		break;

	case ('}'):
		currentLoadedFile->GetNextCharacter();
		specialType = SpecialCharacterRightCurlyBrace;
		isSpecialCharacter = true;
		break;

		//"->"
	case ('-'):

		currentLoadedFile->GetNextCharacter();
		if(currentLoadedFile->LookNextCharacter() == '>')
		{
			currentLoadedFile->GetNextCharacter();
			specialType = SpecialCharacterTheArrowOperator;
			isSpecialCharacter = true;

		}
		else 
		{
			currentLoadedFile->RewindCharacter();
		}
		break;

	}

	if (isSpecialCharacter == true)
	{
		myUnit.subtype = specialType; 
		CompilerData->Units->AddUnit(myUnit);
	}

#ifdef TRACE
	if(isSpecialCharacter)
	{
        CompilerData->LogTrace->ReportLine("Special character is recognized.");
	}
	else if(isComment)
	{
		CompilerData->LogTrace->ReportLine("Comment is recognized.");
	}
	else
	{
        CompilerData->LogTrace->ReportLine("Neither special character nor comment is recognized.");
	}
	CompilerData->LogTrace->ReportExit("LexicSpecialCharacter");
#endif

	return isSpecialCharacter || isComment;
}

bool LexicAnalyzer::LexicIdentifier()
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("LexicIdentifier");
#endif

	bool firstLetter;
	bool condition;
	char c;
	std::string word;
	int keywordsCount;
	int i;

	// populate the generic lexic unit now because we might need to 
	// look at the next character in the currentLoadedFile and that 
	// would change these parameters
	LexicUnit unit;
	unit.id = CompilerData->Units->uniformCharacters->GetCount();
	unit.sourceColumnId = currentLoadedFile->GetCurrentColumn();
	unit.sourceLineId = currentLoadedFile->GetCurrentLine();
	unit.sourceFileId = currentLoadedFile->GetCurentFileID();

	// let's make a fied of keywords
	// If we change this keyword list 
	// we need to change the variable keywordCount too (the variable is after the list of keywords)
	std::string keywords[]=
	{	
		"using",
			"as",
			"namespace",
			"int",
			"float",
			"bool",
			"state",
			"time",
			"void",
			"Facility",
			"Storage",
			"Queue",
			"ADTable",
			"Group",
			"OutputStream",
			"enum",
			"class",
			"abstract",
			"public",
			"private",
			"protected",
			"template",
			"const",
			"static",
			"override",
			"virtual",
			"final",
			"read",
			"write",
			"start",
			"process",
			"if",
			"else",
			"switch",
			"case",
			"default",
			"while",
			"do",
			"for",
			"break",
			"continue",
			"goto",
			"return",
			"with",
			"stop",
			"derivation",
			"numeric",
			"discrete",
			"continuous",
			"INF",
			"model",
			"in",
			"out",
			"define",
			"generate",
			"upto",
			"after",
			"every",
			"terminate",
			"advance",
			"enter",
			"units",
			"forming",
			"leave",
			"from",
			"seize",
			"release",
			"inqueue",
			"outqueue",
			"arrive",
			"depart",
			"wait",
			"on",
			"until",
			"then",
			"timeout",
			"join",
			"group",
			"create",
			"send",
			"to",
			"split",
			"into",
			"gather",
			"and",
			"destroy",
			"execute",
			"exec",
			"simulation",
			"configuration",
			"run",
			"simulations",
			"clear",
			"reset",
			"null",
			"new",
			"instance",
			"of",
         "trace"
	};
	keywordsCount = 99;

	word = "";
	firstLetter = true;

#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Entering while loop for getting string of keyword or identifer.");
#endif
	// this while loop is to get the string of this keyword/identifier
	while(1){

		c=currentLoadedFile->GetNextCharacter();

		// lets test if the read charachter satisfies the condition
		if(firstLetter)
		{
			firstLetter = false;
			condition = (isalpha(c) || c=='_');
		}
		else
		{
			condition= (isalnum(c) || c=='_');
		}

		// if the character satisfies the condition then 
		// connect the character to the word
		if(condition)
		{
			// connect the character c to the end of the word
			word += c;
		}
		else
		{
			// end of word reached
			currentLoadedFile->RewindCharacter();
			break;
		}
	}
#ifdef TRACE
    CompilerData->LogTrace->ReportLine("Exiting while loop for getting string of keyword or identifer.");
	CompilerData->LogTrace->ReportValue("word", word.c_str());
#endif

	// check if the word is true false constant
	if(strcmp(word.c_str(), "true")==0)
	{
		// word is boolean constant "true"
		unit.type = LUTypeConstantBool;
		CompilerData->Units->AddUnit(unit, const_cast<char*>(word.c_str()));
#ifdef TRACE
		CompilerData->LogTrace->ReportLine("Boolean constant \"true\" detected.");
		CompilerData->LogTrace->ReportExit("LexicIdentifier");
#endif
		return true;
	}
	else if(strcmp(word.c_str(), "false")==0)
	{
		// word is boolean constant "false"
		unit.type = LUTypeConstantBool;
		CompilerData->Units->AddUnit(unit, const_cast<char*>(word.c_str()));
#ifdef TRACE
		CompilerData->LogTrace->ReportLine("Boolean constant \"false\" detected.");
		CompilerData->LogTrace->ReportExit("LexicIdentifier");
#endif
		return true;
	}

	// check if the word is a keyword
	for(i=0;i<keywordsCount;i++)
	{
		if(strcmp(keywords[i].c_str(),word.c_str())==0)
		{
			// word is keyword[i]
			unit.type = LUTypeKeyword;
			// subtype is a enumeration. An enumeration are "using", "as"... but they are synonims for integers 0,1,...
			// the list in this metod is ordered in the same order the enumeration in the header file.
			// So we can assign the subtype value as a index number.
			unit.subtype = i;
			// the lexic unit is now filled with data
			CompilerData->Units->AddUnit(unit);
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Keyword detected.");
			CompilerData->LogTrace->ReportExit("LexicIdentifier");
#endif
			return true;
		}
	}

	// the word is identifier
	unit.type = LUTypeIdentifier;
	CompilerData->Units->AddUnit(unit, const_cast<char*>(word.c_str()));


#ifdef TRACE
	CompilerData->LogTrace->ReportLine("Identifier detected.");
	CompilerData->LogTrace->ReportExit("LexicIdentifier");
#endif	

	return true;
}

/*
Numeric constant recognition method.
Simple deterministic finite automaton detecting integer and float constants.
*/
bool LexicAnalyzer::LexicNumericConstant()
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("LexicNumericConstant");
#endif

	// used to determine unit type (true=float, false=int)
	bool scanSuccessfulFloat = false;

	// determine whether error was found
	bool scanSuccessful = false;

	// first we want to save current position in gpss source file
	LexicUnit myLexicUnit;
	myLexicUnit.id = CompilerData->Units->uniformCharacters->GetCount();
	myLexicUnit.sourceColumnId = currentLoadedFile->GetCurrentColumn();
	myLexicUnit.sourceLineId = currentLoadedFile->GetCurrentLine();
	myLexicUnit.sourceFileId = currentLoadedFile->GetCurentFileID();

	// we will use this to collect constant number symbols
	std::string currentNumber = "";

	// since this is finite state machine (automaton), we have to track states
	char currentState = 0;

	// following symbols after legal numeric constant
	std::string symbols = "\t +-*/^%=)]}|&<>!;,:\n";

	// initial actions for digits or '.'
	// note that if this method is called, this char has to be digit or '.' (decimal separator)
	char c = currentLoadedFile->GetNextCharacter();
	if(isdigit(c))
	{
		currentState = 1;
		currentNumber += c;
	}
	else
	{
		currentState = 2;
		currentNumber += "0.";
	}

	// scan current sequence
	while(1)
	{
		c = currentLoadedFile->GetNextCharacter();
		if(currentState == 1)
		{
			if(isdigit(c))
			{
				currentState = 1;  // just for clarity
				currentNumber += c;
			}
			else if(c == '.')
			{
				currentState = 2;
				currentNumber += c;
			}
			else if(isalpha(c))
			{
				// if next char is letter of alphabet then this is an error 'bad suffix number'
				// ERROR message 'bad suffix on number'
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_BAD_SUFFIX_NUMBER);
#ifdef TRACE
				CompilerData->LogTrace->ReportLine("Bad suffix on number found.");
#endif
				scanSuccessfulFloat = false;
				scanSuccessful = false;
				break;
			}
			else if(symbols.find(c) != std::string::npos)
			{
				// so far, we have only digits and one legal symbol was found - number must be an integer
				scanSuccessfulFloat = false;
				scanSuccessful = true;
				break;
			}
			else
			{
				// some other symbol found
				// ERROR: unespected symbol found
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_UNEXPECTED_SYMBOL);
#ifdef TRACE
				CompilerData->LogTrace->ReportLine("Unexpected symbol found.");
#endif
				scanSuccessfulFloat = false;
				scanSuccessful = false;
			}
		}
		else if(currentState == 2)
		{
			if(isdigit(c))
			{
				currentState = 3;
				currentNumber += c;
			}
			else
			{
				// report error
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_NO_DIGIT_AFTER_DECIMAL_DOT);
				// last char is decimal separator '.' and trailing '0' (zero) is added
				// after error correction, float remains
				//currentNumber.erase(currentNumber.size()-1);
				currentNumber += "0";
				scanSuccessfulFloat = true;
				scanSuccessful = false;
				break;
			}
		}
		else if(currentState == 3)
		{
			if(isdigit(c))
			{
				currentState = 3;
				currentNumber += c;
			}
			else if(c == 'E')
			{
				currentNumber += c;
				currentState = 4;
			}
			else if(isalpha(c))
			{
				// if next char is letter of alphabet then this is an error 'bad suffix number'
				// ERROR message 'bad suffix on number'
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_BAD_SUFFIX_NUMBER);
#ifdef TRACE
				CompilerData->LogTrace->ReportLine("Bad suffix on number found.");
#endif
				scanSuccessfulFloat = true;
				scanSuccessful = false;
				break;
			}
			else if(symbols.find(c) != std::string::npos)
			{
				// so far, we have only digits and one legal symbol was found - number must be a float
				scanSuccessfulFloat = true;
				scanSuccessful = true;
				break;
			}
			else
			{
				// some unexpected symbol found
				// ERROR message: 'unexpected symbol found'
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_UNEXPECTED_SYMBOL);
#ifdef TRACE
				CompilerData->LogTrace->ReportLine("Unexpected symbol found.");
#endif
				scanSuccessfulFloat = true;
				scanSuccessful = false;
				break;
			}
		}
		else if(currentState == 4)
		{
			if(c=='+' || c=='-')
			{
				currentNumber += c;
				currentState = 5;
			}
			else if(isdigit(c))
			{
				currentNumber += c;
				currentState = 6;
			}
			else
			{
				// error report
				// error correction action - delete trailing 'E'
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_WRONG_SYMBOL_AFTER_EXPONENT);
				// after error correction float remains
				currentNumber.erase(currentNumber.size()-1);
				scanSuccessfulFloat = true;
				scanSuccessful = false;
				break;
			}
		}
		else if(currentState == 5)
		{
			if(isdigit(c))
			{
				currentNumber += c;
				currentState = 6;
			}
			else
			{
				// report error
				// erase 2 trailing chars
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_NO_DIGIT_AFTER_EXPONENT_SIGN);
				// after error correction float remains
				currentNumber.erase(currentNumber.size()-2);
				scanSuccessfulFloat = true;
				scanSuccessful = false;
				break;
			}
		}
		else if(currentState == 6)
		{
			if(isdigit(c))
			{
				currentNumber += c;
				currentState = 6; // just for clarity
			}
			else if(isalpha(c))
			{
				// if next char is letter of alphabet then this is an error 'bad suffix number'
				// ERROR message 'bad suffix on number'
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_BAD_SUFFIX_NUMBER);
#ifdef TRACE
				CompilerData->LogTrace->ReportLine("Bad suffix on number found.");
#endif
				scanSuccessfulFloat = true;
				scanSuccessful = false;
				break;
			}
			else if(symbols.find(c) != std::string::npos)
			{
				// so far, we have only digits and one legal symbol was found - number must be a float
				scanSuccessfulFloat = true;
				scanSuccessful = true;
				break;
			}
			else
			{
				// some unexpected symbol found
				// ERROR message: 'unexpected symbol found'
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_UNEXPECTED_SYMBOL);
#ifdef TRACE
				CompilerData->LogTrace->ReportLine("Unexpected symbol found.");
#endif
				scanSuccessfulFloat = true;
				scanSuccessful = false;
				break;
			}
		}
		else
		{
			// nothing here, probably not needed at all but just in case...
		}
	}

	// while loop is exited after finding first symbol that does not define numeric constant
	// that's why current position in gpss++ src file should rewinded (one place back)
	currentLoadedFile->RewindCharacter();

	// set all unit type parameters and fill the table
	if(scanSuccessfulFloat)
	{
		myLexicUnit.type = LUTypeConstantFloat;
	}
	else
	{
		myLexicUnit.type = LUTypeConstantInteger;
	}
	CompilerData->Units->AddUnit(myLexicUnit, const_cast<char*>(currentNumber.c_str()));

#ifdef TRACE
	if(scanSuccessfulFloat)
	{
		CompilerData->LogTrace->ReportLine("Floating point constant detected.");
	}
	else
	{
		CompilerData->LogTrace->ReportLine("Integer constant detected.");
	}
	CompilerData->LogTrace->ReportExit("LexicNumericConstant");
#endif

	// depends whether one of number constant units was recognized
	return scanSuccessful;
}

/*
String recognition method.
if newline '\n' found - generate warning, accept currentString;
if unexpected EOF == -1 found - generate warning, accept currentString;
if backslash '\' found - further checking needed, ('"','t','n','\') chars only accepted;
if '"' is found - add to unit table and exit;
else everything allowed?
*/
bool LexicAnalyzer::LexicStringConstant()
{
#ifdef TRACE
	CompilerData->LogTrace->ReportEntry("LexicStringConstant");
#endif

	// at this moment our pointer is pointing to first place before '"'
	// now move pointer onto '"' and declare char c variable at the same time
	char c = currentLoadedFile->GetNextCharacter();

	// set false if error occurs
	bool scanSuccessful = true;

	// first we want to save current position in gpss source file
	LexicUnit myLexicUnit;
	myLexicUnit.id = CompilerData->Units->uniformCharacters->GetCount();
	myLexicUnit.sourceColumnId = currentLoadedFile->GetCurrentColumn();
	myLexicUnit.sourceLineId = currentLoadedFile->GetCurrentLine();
	myLexicUnit.sourceFileId = currentLoadedFile->GetCurentFileID();

	// since std::string is ok by ANSI/ISO we will use it to collect chars
	// requires directive #include <string>
	std::string currentString = "";

	// come on, let's scan this gpss++ string :)
	while(1)
	{
		c = currentLoadedFile->GetNextCharacter();
		if (c == '\n')
		{
			// end of line found, something is wrong with the source
			// stop scanning string
			// TODO: print error message like: Unexpected end of line.
			CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_STRING_UNEXPECTED_END_OF_LINE);
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Unexpected end of file - illegal \\n found.");
#endif
			scanSuccessful = false;
			break;
		}
		if (c == -1)
		{
			// unexpected end of file found, something is wrong with the source
			// stop scanning string
			// TODO: print error message like: Unexpected end of file.
			CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_STRING_UNEXPECTED_END_OF_FILE);
#ifdef TRACE
			CompilerData->LogTrace->ReportLine("Unexpected end of file - (-1) found.");
#endif
			scanSuccessful = false;
			break;
		}
		else if (c == '\\')
		{
			c = currentLoadedFile->LookNextCharacter();
			if (c == '\\' || c == 't' || c == 'n' || c == '"')
			{
				currentString += '\\';
				currentString += c;
				currentLoadedFile->GetNextCharacter(); // just moving char pointer one char ahead
				continue;
			}
			else
			{
				// TODO: some error message for illegal escape sequence
				// '\' is ignored and we can continue with scanning
				CompilerData->ErrorWarningReport->ReportError(&myLexicUnit, ERR_LEX_STRING_SOLO_BACKSLASH);
#ifdef TRACE
				CompilerData->LogTrace->ReportLine("Ilegal backslash - ignored.");
#endif
				scanSuccessful = false;
				continue;
			}
		}
		else if (c == '"')
		{
			// this is the end of gpss++ string, no more scanning
			break;
		}
		else
		{
			// c can be any other character
			currentString += c;
		}
	}

#ifdef TRACE
	if(scanSuccessful)
	{
        CompilerData->LogTrace->ReportLine("String constant successfuly recognized.");
	}
	else
	{
        CompilerData->LogTrace->ReportLine("String constant was not successfuly recognized.");
	}
	CompilerData->LogTrace->ReportValue("currentString", currentString.c_str());
#endif

	// set all needed parameters and fill the table
	myLexicUnit.type = LUTypeConstantString;
	CompilerData->Units->AddUnit(myLexicUnit, const_cast<char*>(currentString.c_str()));

#ifdef TRACE
	CompilerData->LogTrace->ReportExit("LexicStringConstant");
#endif

	// if scanning completed without errors return true
	// if error occured return false
	return scanSuccessful;
}

